import json
import logging
from datetime import datetime

from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.jobstores.base import JobLookupError
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger
from sqlmodel import Session, select

from .Database import engine
from models.models import ScheduledJob

logger = logging.getLogger(__name__)

class DatabaseScheduler:
    def __init__(self):
        # 配置作业存储
        jobstores = {
            "default": SQLAlchemyJobStore(engine=engine)
        }

        # 配置执行器
        executors = {
            "default": ThreadPoolExecutor(20)
        }

        # 配置调度器
        job_defaults = {
            "coalesce": True,
            "max_instances": 3
        }
        self.scheduler = BackgroundScheduler(
            jobstores=jobstores,
            executors=executors,
            job_defaults=job_defaults
        )

        # 导入任务函数的映射
        self.task_functions = {}

    def register_task(self,name:str, func):
        """注册任务函数"""
        self.task_functions[name] = func
        logger.info(f"注册任务：{name}")

    async def start(self):
        """启动调度器"""
        if not self.scheduler.running:
            logger.info("启动调度器")
            self.scheduler.start()

    async def shutdown(self):
        """关闭调度器"""
        if self.scheduler.running:
            logger.info("关闭调度器")
            self.scheduler.shutdown()

    def add_cron_job(self,
                     task_name: str,
                     cron_expression: str,
                     job_id: str,
                     name: str,
                     job_args: list = None,
                     job_kwargs: dict = None,
                     db: Session = None):
        """添加cron定时任务"""
        try:
            # 检查任务函数是否存在
            if task_name not in self.task_functions:
                raise ValueError(f"任务函数{task_name}未注册")

            # 确保 job_kwargs 包含 job_id
            if job_kwargs is None:
                job_kwargs = {}
            job_kwargs['job_id'] = job_id  # 添加 job_id 到 kwargs 中

            # 解析cron表达式
            trigger = CronTrigger.from_crontab(cron_expression)
            self.scheduler.add_job(
                func = self.task_functions[task_name],
                trigger = trigger,
                id = job_id,
                name = name,
                args = job_args or [],
                kwargs = job_kwargs or {}
            )

            # 保存到数据库
            if db:
                scheduled_job = ScheduledJob(
                    job_id=job_id,
                    name=name,
                    task_function=task_name,
                    cron_expression=cron_expression,
                    job_args = json.dumps(job_args) if job_args else None,
                    job_kwargs = json.dumps(job_kwargs) if job_kwargs else None,
                    is_active=True
                )
                db.add(scheduled_job)
                db.commit()
            logger.info(f"添加cron任务：{job_id}")
            return True
        except Exception as e:
            logger.error(f"添加cron任务失败：{e}")
            self.scheduler.remove_job(job_id)
            if db:
                db.rollback()
            return False

    def add_interval_job(self,
                         task_name: str,
                         seconds: int,
                         job_id: str,
                         name: str,
                         job_args: list = None,
                         job_kwargs: dict = None,
                         db: Session = None):
        """添加间隔定时任务"""
        try:
            # 检查任务函数是否存在
            if task_name not in self.task_functions:
                raise ValueError(f"任务函数{task_name}未注册")

            # 确保 job_kwargs 包含 job_id
            if job_kwargs is None:
                job_kwargs = {}
            job_kwargs['job_id'] = job_id  # 添加 job_id 到 kwargs 中

            # 添加到APScheduler
            self.scheduler.add_job(
                func=self.task_functions[task_name],
                trigger=IntervalTrigger(seconds=seconds),
                id=job_id,
                name=name,
                args=job_args or [],
                kwargs=job_kwargs or {}
            )

            # 保存到数据库
            if db:
                scheduled_job = ScheduledJob(
                    job_id=job_id,
                    name=name,
                    task_function=task_name,
                    interval_seconds=seconds,
                    job_args=json.dumps(job_args) if job_args else None,
                    job_kwargs=json.dumps(job_kwargs) if job_kwargs else None,
                    is_active=True
                )
                db.add(scheduled_job)
                db.commit()
            logger.info(f"添加间隔任务：{job_id}")
            return True
        except Exception as e:
            logger.error(f"添加间隔任务失败：{e}")
            self.scheduler.remove_job(job_id)
            if db:
                db.rollback()
            return False

    def pause_job(self, job_id: str, db: Session=None):
        """暂停任务"""
        try:
            self.scheduler.pause_job(job_id)

            # 更新数据库状态
            if db:
                statement = select(ScheduledJob).where(ScheduledJob.job_id == job_id).with_for_update()
                job = db.exec(statement).first()
                if job:
                    job.is_active = False
                    job.updated_time = datetime.now()
                    db.commit()
            logger.info(f"暂停任务：{job_id}")
            return True
        except JobLookupError:
            logger.error(f"任务不存在：{job_id}")
            return False
        except Exception as e:
            logger.error(f"暂停任务失败：{e}")
            if db:
                db.rollback()
            return False

    def resume_job(self,job_id: str, db: Session = None):
        """恢复任务"""
        try:
            self.scheduler.resume_job(job_id)

            # 恢复数据库状态
            if db:
                statement = select(ScheduledJob).where(ScheduledJob.job_id == job_id).with_for_update()
                job = db.exec(statement).first()
                if job:
                    job.is_active = True
                    job.updated_time = datetime.now()
                    db.commit()
            logger.info(f"恢复任务：{job_id}")
            return True
        except JobLookupError:
            logger.error(f"任务不存在：{job_id}")
            return False
        except Exception as e:
            logger.error(f"恢复任务失败：{e}")
            if db:
                db.rollback()
            return False

    def remove_job(self, job_id: str, db: Session = None):
        """删除任务"""
        try:
            self.scheduler.remove_job(job_id)

            # 删除数据库记录
            if db:
                statement = select(ScheduledJob).where(ScheduledJob.job_id == job_id).with_for_update()
                job = db.exec(statement).first()
                if job:
                    db.delete(job)
                    db.commit()
            logger.info(f"删除任务：{job_id}")
            return True
        except JobLookupError:
            logger.error(f"任务不存在：{job_id}")
            return False
        except Exception as e:
            logger.error(f"删除任务失败：{e}")
            if db:
                db.rollback()
            return False

    def modify_job_cron(self, job_id: str, cron_expression: str, db: Session = None):
        """修改任务cron表达式"""
        try:
            # 移除旧任务
            self.scheduler.remove_job(job_id)
            # 获取原任务信息
            if db:
                statement = select(ScheduledJob).where(ScheduledJob.job_id == job_id).with_for_update()
                job = db.exec(statement).first()
                if job and job.task_function in self.task_functions:
                    # 解析参数
                    job_args = json.loads(job.job_args) if job.job_args else []
                    job_kwargs = json.loads(job.job_kwargs) if job.job_kwargs else {}

                    # 添加新任务
                    trigger = CronTrigger.from_crontab(cron_expression)
                    self.scheduler.add_job(
                        func=self.task_functions[job.task_function],
                        trigger=trigger,
                        id=job_id,
                        name=job.name,
                        args=job_args,
                        kwargs=job_kwargs
                    )

                    # 更新数据库
                    job.cron_expression = cron_expression
                    job.updated_time = datetime.now()
                    db.commit()

                    logger.info(f"修改任务：{job_id}")
                    return True
                return False
        except Exception as e:
            logger.error(f"修改任务Cron表达式失败：{e}")
            if db:
                db.rollback()
            return False

    def list_jobs(self,db: Session = None):
        """列出所有任务"""
        jobs = []
        for job in self.scheduler.get_jobs():
            job_info = {
                "id": job.id,
                "name": job.name,
                "next_run_time": job.next_run_time.strftime('%Y-%m-%d %H:%M:%S') if job.next_run_time else None,
                "trigger": str(job.trigger),
                "pending": job.pending
            }

            # 从数据库获取额外信息
            if db:
                statement = select(ScheduledJob).where(ScheduledJob.job_id == job.id)
                db_job = db.exec(statement).first()
                if db_job:
                    job_info.update({
                        "is_active": db_job.is_active,
                        "task_function": db_job.task_function,
                        "created_time": db_job.created_time.strftime('%Y-%m-%d %H:%M:%S') if db_job.created_time else None,
                    })
            jobs.append(job_info)

        return jobs

# 初始化调度器实例
db_scheduler = DatabaseScheduler()





